package cn.flying.cloud.base.common.utils.lang;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.flying.cloud.base.common.annotation.Column;

/**
 * jdbc工具类
 *
 * @author: admin
 * @date: 2024年04月07日 11:44
 * @version: 1.0
 */
public class JdbcUtil {
    private static final Logger logger = LoggerFactory.getLogger(JdbcUtil.class);

    private static final ThreadLocal<Connection> connectionCache = new ThreadLocal<>();
    private static final ThreadLocal<PreparedStatement> statementCache = new ThreadLocal<>();
    private static final ThreadLocal<ResultSet> resultSetCache = new ThreadLocal<>();

    // 静态代码块加载JDBC驱动
    static {
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            throw new RuntimeException("Failed to load JDBC Driver!", e);
        }
    }

    /**
     * 获取数据库连接
     *
     * @param url
     * @param user
     * @param password
     * @return
     */
    public static Connection getConnect(String url, String user, String password) {
        Connection connection = connectionCache.get();
        if (connection != null) {
            return connection;
        }
        try {
            connection = DriverManager.getConnection(url, user, password);
            connectionCache.set(connection);
            return connection;
        } catch (SQLException e) {
            throw new RuntimeException("Failed to get Database Connection!", e);
        }
    }

    /**
     * 关闭数据库连接资源
     */
    public static void closeConnect() {
        try {
            Connection connection = connectionCache.get();
            if (connection != null) {
                connection.close();
            }
        } catch (Exception e) {
            logger.error("Failed to Release Database Resource!", e);
        } finally {
            connectionCache.remove();
        }
    }

    /**
     * 释放数据库连接资源
     */
    public static void release() {
        try {
            ResultSet resultSet = resultSetCache.get();
            if (resultSet != null) {
                resultSet.close();
            }
            PreparedStatement statement = statementCache.get();
            if (statement != null) {
                statement.close();
            }
            Connection connection = connectionCache.get();
            if (connection != null) {
                connection.close();
            }
        } catch (Exception e) {
            logger.error("Failed to Release Database Resource!", e);
        } finally {
            resultSetCache.remove();
            statementCache.remove();
            connectionCache.remove();
        }
    }

    /**
     * 执行查询操作
     *
     * @param sql
     * @param params
     */
    public static ResultSet executeQuery(Connection connection, String sql, Object... params) throws Exception {
        PreparedStatement statement = null;
        ResultSet resultSet;
        try {
            statement = connection.prepareStatement(sql);
            statementCache.set(statement);
            if (params != null) {
                for (int i = 0; i < params.length; i++) {
                    statement.setObject(i + 1, params[i]);
                }
            }
            resultSet = statement.executeQuery();
            resultSetCache.set(resultSet);
            return resultSet;
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 执行查询操作
     *
     * @param connection
     * @param sql
     * @param clazz
     * @param params
     * @param <T>
     * @return
     * @throws Exception
     */
    public static <T> List<T> executeQuery(Connection connection, String sql, Class<T> clazz, Object... params) throws Exception {
        ResultSet resultSet = executeQuery(connection, sql, params);
        List<T> list = convertToObject(resultSet, clazz);
        if (resultSet != null) {
            resultSet.close();
            resultSetCache.remove();
        }
        PreparedStatement statement = statementCache.get();
        if (statement != null) {
            statement.close();
            statementCache.remove();
        }
        return list;
    }

    /**
     * 映射结果集
     *
     * @param rs
     * @param clazz
     * @param <T>
     * @return
     * @throws Exception
     */
    public static <T> List<T> convertToObject(ResultSet rs, Class<T> clazz) throws Exception {
        List<T> objects = new ArrayList<>();
        if (rs == null || !rs.next()) {
            return objects;
        }

        do {
            T object = clazz.getDeclaredConstructor().newInstance();

            // 获取所有带有@Column注解的字段
            for (Field field : clazz.getDeclaredFields()) {
                if (field.isAnnotationPresent(Column.class)) {
                    Column column = field.getAnnotation(Column.class);
                    String columnName = column.value();

                    // 使私有字段可访问
                    field.setAccessible(true);

                    // 从ResultSet获取值并设置到对象
                    try {
                        Object value = rs.getObject(columnName);
                        field.set(object, value);
                    } catch (SQLException e) {
                        logger.error("Error setting field: " + field.getName() + " from column: " + columnName);
                    }
                }
            }
            objects.add(object);
        } while (rs.next());

        return objects;
    }
}
